#ifndef GEMO_H
#define GEMO_H

#include <vector>
#include <math.h>
#include <QMetaType>



class Point2d{
public:
    Point2d(){x = 0.0; y = 0.0;}
    Point2d(double _x, double _y){x = _x; y = _y;}
public:
    double x;
    double y;
};

class Vector2d: public Point2d{
public:
    Vector2d(){x = 0.0; y = 0.0;}
    //Vector2d(double _x, double _y){x = _x; y = _y;}
    Vector2d(Point2d sta, Point2d end){x = end.x - sta.x; y = end.y - sta.y;}
    const double length() const {return sqrt(x*x+y*y);}
    const double inner_product(const Vector2d & vec) const {return (x*vec.x + y*vec.y);}
    void rotate90(){double temp = x; x = y; y = -temp;}
    void rotate180(){x = -x; y = -y;}
    Vector2d & operator /=(const double ratio){x /= ratio; y /= ratio; return *this;}
    Vector2d & operator *=(const double ratio){x *= ratio; y *= ratio; return *this;}
    Vector2d & operator +=(const Vector2d & vec){x += vec.x; y += vec.y; return *this;}
    Vector2d & operator -=(const Vector2d & vec){x -= vec.x; y -= vec.y; return *this;}
    const Vector2d operator +(const Vector2d &other) const {
      return Vector2d(*this) += other;
    }

    const Vector2d operator -(const Vector2d &other) const {
      return Vector2d(*this) -= other;
    }

    friend const Vector2d operator *(const double left, const Vector2d &other){
      return Vector2d(other) *= left;
    }

    friend const Vector2d operator *(const Vector2d &other, const double right){
      return Vector2d(other) *= right;
    }

    friend const Vector2d operator /(const double left, const Vector2d &other){
      return Vector2d(other) /= left;
    }

    friend const Vector2d operator /(const Vector2d &other, const double right){
      return Vector2d(other) /= right;
    }
};

class Segment2d{
    public:
        Segment2d(){A.x = 0.0; A.y = 0.0;B.x = 0.0; B.y = 0.0;}
        Segment2d(Point2d _A, Point2d _B){A.x = _A.x; A.y = _A.y; B.x = _B.x; B.y = _B.y;}
    public:
        Point2d A;
        Point2d B;
};

// compute the collision time between a moving
// point and a moving segment

double CollisionTime(Point2d p0, Point2d p1, Point2d p2,
                     Vector2d v0, Vector2d v1, Vector2d v2,
                     double &s1, double &s2);
//{
//    Vector2d v21 = v2 - v1;
//    Vector2d p21(p1,p2);
//    Vector2d p01(p1,p0);
//    Vector2d v01 = v0 - v1;

//    double a1 = -p01.x;
//    double a2 =  p21.x;
//    double a3 =  v01.x;
//    double a4 = -v21.x;

//    double b1 = -p01.y;
//    double b2 =  p21.y;
//    double b3 =  v01.y;
//    double b4 = -v21.y;

//    double A = a2*b4 - a4*b2;
//    double B = a2*b3 - a3*b2 + a1*b4 - a4*b1;
//    double C = a1*b3 - a3*b1;

//    double s1 = 0.0;
//    double s2 = 0.0;

//    double time;

//    if(fabs(A)<1e-16){
//        if(fabs(B)>=1e-16){
//               s1 = -C / B;
//               s2 = -C / B;
//        }else
//        {
//            if(fabs(C)>=1e-16)
//                return -1.0;
//        }
//    }else{
//        if((B*B - 4*A*C)>0.0){
//            s1 = (-B + sqrt(B*B - 4*A*C))/A/2.0;
//            s2 = (-B - sqrt(B*B - 4*A*C))/A/2.0;
//        }else{
//            time = -1.0;
//            return time;
//        }
//    }

//    time = -1.0;
//    if(s1 >=0.0 && s1 <= 1.0 ){
//        double tt;
//        if(fabs(a3+a4*s1)<1e-12){
//            if(fabs(b3+b4*s1)<1e-12){
//                if(fabs(b1*a2-a1*b2)<1e-12){
//                    time = 0.0;

//                    return time;
//                }else{
//                    time = -2.0;

//                    return time;
//                }
//            }else{
//                tt = (b1+b2*s1)/(b3+b4*s1);
//            }
//        }else{
//            tt = (a1+a2*s1)/(a3+a4*s1);
//        }
//        if(tt >= 0.0 )
//            time = tt;
//     }

//    if(s2 >=0.0 && s2 <= 1.0 ){
//        double tt;
//         if(fabs(a3+a4*s1)<1e-12){
//            if(fabs(b3+b4*s1)<1e-12){
//                if(fabs(b1*a2-a1*b2)<1e-12){
//                    time = 0.0;
//                    return time;
//                }else{
//                    time = -2.0;
//                    return time;
//                }
//            }else{
//                tt = (b1+b2*s1)/(b3+b4*s1);
//            }
//          }else{
//            tt = (a1+a2*s2)/(a3+a4*s2);
//          }

//        if(tt >= 0.0 )
//            time = (time > 0.0 ? std::min(tt, time):tt);
//    }

//    return time;
//}

class MPolygon{
public:
    MPolygon(){points.resize(0,Point2d());}
public:
    int const PointNo() const {return points.size();}
    std::vector<Point2d> points;
    std::vector<Vector2d> normals;
    Vector2d Segment(int idx);
    void iArea(std::vector<double> &Ai, int jump);
    double SmallestArc();
    double Area();
    void subdivision();
    void remesh(double criteria);
    void reorder(double criteria, std::vector<int> &Token);

};


void splitPolygon(MPolygon TPoly,
                  std::vector<int> TouchPoint,
                  std::vector<int> Segments,
                  std::vector<MPolygon> &Polygons);
Q_DECLARE_METATYPE(MPolygon);
#endif // GEMO_H
